package com.addzero.kmp.processor

import cn.hutool.json.JSONUtil
import com.addzero.kmp.consts.GEN_PKG
import com.addzero.kmp.generrator.generateMetadataCode
import com.addzero.kmp.processor.entity.JdbcTableMetadata
import com.addzero.kmp.util.CodeGeneratorUtil
import com.addzero.kmp.util.TypeMapper
import com.addzero.kmp.util.TypeMapper.toBigCamelCase
import com.addzero.kmp.util.TypeMapper.toLowCamelCase
import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.symbol.KSAnnotated
import java.security.MessageDigest

/**
 * JDBC元数据提取器
 *
 * 功能：直接连接到数据库，读取表结构，生成JSON格式的元数据
 */
class JdbcMetadataEntityProcessor(
    private val codeGenerator: CodeGenerator,
    private val options: Map<String, String>
) : SymbolProcessor {

    // 输出目录配置
    private val outputPackage = options["outputPackage"] ?: GEN_PKG
    private val outputFileName = options["outputFileName"] ?: "JdbcMetadata"


    override fun process(resolver: Resolver): List<KSAnnotated> {
        try {
            val tables = com.addzero.kmp.util.JdbcMetadataExtractor.initAndGetJdbcMetaDataTables(options)

            // 生成接口文件
            val dependencies = Dependencies(aggregating = true)
            generateKotlinClasses(tables, dependencies)

            generateMetadataCode(outputPackage, codeGenerator, tables)

        } catch (e: Exception) {
            println("JDBC元数据处理发生错误: ${e.message}")
            e.printStackTrace()
        }

        return emptyList()
    }


    /**
     * 生成Kotlin类文件 - 简化实现，确保文件生成
     */
    private fun generateKotlinClasses(tables: List<JdbcTableMetadata>, dependencies: Dependencies) {
        // 收集所有不支持的类型
        val unsupportedTypes = mutableSetOf<Pair<String, String>>()

        // 为每个表生成一个接口文件
        tables.forEach { table ->
            try {
                // 使用大驼峰命名（带I前缀）
                val interfaceName = "I" + table.tableName.split("_").joinToString("") {
                    it.replaceFirstChar { char -> char.uppercase() }
                }
                val basePackage = "$outputPackage.${table.schema}"
                val interfacePackage = "$basePackage.table"
                val implPackage = "$interfacePackage.impl"

                // 获取模块源代码目录
                val srcDir = options["module.main.src.dir"] ?: run {
                    println("模块源代码目录未配置 (module.main.src.dir)，将使用KSP默认输出目录")
                    null
                }

                // 生成接口文件
                val interfaceContent =
                    generateInterfaceForTable(table, interfacePackage, interfaceName, unsupportedTypes)
                if (srcDir != null) {
                    val interfaceFilePath = "${srcDir}/${interfacePackage.replace('.', '/')}/${interfaceName}.kt"
                    val interfaceFile = java.io.File(interfaceFilePath)
                    interfaceFile.parentFile?.mkdirs()
                    interfaceFile.writeText(interfaceContent)
                    println("生成接口到源代码目录: $interfaceFilePath")
                } else {
                    codeGenerator.createNewFile(
                        dependencies = dependencies,
                        packageName = interfacePackage,
                        fileName = interfaceName
                    ).use { output ->
                        output.write(interfaceContent.toByteArray())
                    }
                }

                // 生成实现类文件
                val implName = "${interfaceName}Impl"
                val implContent =
                    generateImplClass(table, implPackage, interfacePackage, interfaceName, implName, unsupportedTypes)
                if (srcDir != null) {
                    val implFilePath = "${srcDir}/${implPackage.replace('.', '/')}/${implName}.kt"
                    val implFile = java.io.File(implFilePath)
                    implFile.parentFile?.mkdirs()
                    implFile.writeText(implContent)
                    println("生成实现类到源代码目录: $implFilePath")
                } else {
                    codeGenerator.createNewFile(
                        dependencies = dependencies,
                        packageName = implPackage,
                        fileName = implName
                    ).use { output ->
                        output.write(implContent.toByteArray())
                    }
                }

                // 新增：生成表单数据类和 rememberXXXFormState
//                generateFormStateFile(table)

                // 记录生成结果
                println("成功生成接口和实现类: $interfacePackage.$interfaceName, $implPackage.$implName")
            } catch (e: Exception) {
                // 记录错误信息，但不中断处理过程
                println("生成表 ${table.tableName} 接口或实现类失败: ${e.message}")
                e.printStackTrace()
            }
        }

        // 生成 UnSupportSqlType.kt 文件
        if (unsupportedTypes.isNotEmpty()) {
            try {
                val typeAliasContent = generateUnsupportedTypesFile(unsupportedTypes)
                codeGenerator.createNewFile(
                    dependencies = dependencies,
                    packageName = outputPackage,
                    fileName = "UnSupportSqlType"
                ).use { output ->
                    output.write(typeAliasContent.toByteArray())
                }
                println("成功生成不支持类型定义文件: $outputPackage.UnSupportSqlType")
            } catch (e: Exception) {
                println("生成不支持类型定义文件失败: ${e.message}")
                e.printStackTrace()
            }
        }
    }

    private fun generateUnsupportedTypesFile(unsupportedTypes: Set<Pair<String, String>>): String {
        val typeAliases = unsupportedTypes.map { (typeName, _) ->
            "typealias ${typeName.toBigCamelCase()} = String"
        }.joinToString("\n")

        return """
            |package $outputPackage
            |
            |/**
            | * 不支持KMP的SQL类型定义
            | * 这些类型在KMP中统一使用String类型替代
            | */
            |$typeAliases
            |""".trimMargin()
    }


    /**
     * 为单个表生成接口代码
     */
    private fun generateInterfaceForTable(
        table: JdbcTableMetadata,
        packageName: String,
        interfaceName: String,
        unsupportedTypes: MutableSet<Pair<String, String>>
    ): String {
        val tableUnsupportedTypes = mutableListOf<String>()

        // 构建属性部分
        val propertiesCode = table.columns.joinToString("\n\n") { column ->
            val kotlinType = TypeMapper.mapToKotlinType(column)
            if (kotlinType == column.columnType.toBigCamelCase()) {
                unsupportedTypes.add(Pair(column.columnType, kotlinType))
                tableUnsupportedTypes.add("字段名: ${column.columnName}, 字段类型: ${column.columnType}")
            }
            CodeGeneratorUtil.generateProperty(column, kotlinType)
        }

        // 构建类注释
        val classComment = CodeGeneratorUtil.generateClassComment(
            className = interfaceName,
            tableRemarks = table.remarks,
            unsupportedTypes = tableUnsupportedTypes
        )

        return """
            |package $packageName
            |
            |import $outputPackage.*
            |$classComment
            |interface $interfaceName {
            |
            |$propertiesCode
            |
            |}
            |""".trimMargin()
    }

    /**
     * 生成JSON文件
     */
    private fun generateJsonFile(tables: Any, fileName: String) {
        val dependencies = Dependencies(aggregating = true)

        codeGenerator.createNewFile(
            dependencies = dependencies,
            packageName = GEN_PKG,
            fileName = "$fileName.json"
        ).use { output ->

            val toJsonStr = JSONUtil.toJsonStr(tables)
            output.write(toJsonStr.toByteArray())
        }
    }

    /**
     * 生成MD5哈希
     */
    private fun generateMd5(input: String): String {
        val md = MessageDigest.getInstance("MD5")
        val digest = md.digest(input.toByteArray())
        return digest.joinToString("") { "%02x".format(it) }
    }

    /**
     * 表元数据数据类
     */
//    data class JdbcTableMetadata(
//        val tableName: String,
//        val schema: String,
//        val tableType: String,
//        val remarks: String,
//        val columns: List<JdbcColumnMetadata>
//    )
//
//    /**
//     * 列元数据数据类
//     */
//    data class JdbcColumnMetadata(
//        val md5: String,
//        val tableName: String,
//        val columnName: String,
//        val jdbcType: Int,
//        val columnType: String,
//        val columnLength: Int,
//        val nullable: Boolean,
//        val nullableFlag: String,
//        val remarks: String,
//        val defaultValue: String?,
//        var isPrimaryKey: Boolean
//    )

    private fun generateImplClass(
        table: JdbcTableMetadata,
        implPackageName: String,
        interfacePackageName: String,
        interfaceName: String,
        implName: String,
        unsupportedTypes: MutableSet<Pair<String, String>>
    ): String {
        val tableUnsupportedTypes = mutableListOf<String>()
        // 构建构造函数参数
        val constructorParams = table.columns.joinToString(",\n        ") { column ->
            val kotlinType = TypeMapper.mapToKotlinType(column)
            if (kotlinType == column.columnType.toBigCamelCase()) {
                unsupportedTypes.add(Pair(column.columnType, kotlinType))
                tableUnsupportedTypes.add("字段名: ${column.columnName}, 字段类型: ${column.columnType}")
            }
            val camelCaseName = column.columnName.toLowCamelCase()
            "override val $camelCaseName: $kotlinType${if (column.nullable) "?" else ""}"
        }

        // 构建类注释
        val classComment = CodeGeneratorUtil.generateClassComment(
            className = implName,
            interfaceName = interfaceName,
            tableRemarks = table.remarks,
            unsupportedTypes = tableUnsupportedTypes
        )

        return """
            |package $implPackageName
            |
            |import $outputPackage.*
            |import $interfacePackageName.$interfaceName
             import kotlinx.serialization.Serializable
            |
            |$classComment
            |@Serializable
            |data class $implName(
            |    $constructorParams
            |) : $interfaceName
            |""".trimMargin()
    }

}


/**
 * JDBC元数据提取器提供者
 *
 * 用于创建和注册JdbcMetadataExtractor处理器
 */
class JdbcMetadataEntityProvider : SymbolProcessorProvider {
    override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
        println("创建JDBC元数据提取器处理器，配置选项: ${environment.options}")

        // 打印配置信息
        environment.options.forEach { (key, value) ->
            println("配置: $key = $value")
        }

        return JdbcMetadataEntityProcessor(
            codeGenerator = environment.codeGenerator,
            options = environment.options
        )
    }
}
